package repository

import (
	"context"
	"time"

	"github.com/devops-smartbot/devops-smartbot/services/ticket-service/internal/model"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

// MongoRepository implements Repository backed by MongoDB.
type MongoRepository struct {
	collection *mongo.Collection
}

// NewMongoRepository constructs a Mongo-backed repository.
func NewMongoRepository(db *mongo.Database) *MongoRepository {
	return &MongoRepository{collection: db.Collection("tickets")}
}

// ListTickets fetches tickets with simple pagination.
func (r *MongoRepository) ListTickets(ctx context.Context, filter Filter) ([]model.Ticket, int64, error) {
	var tickets []model.Ticket

	mongoFilter := bson.M{}
	if len(filter.Status) > 0 {
		mongoFilter["status"] = bson.M{"$in": filter.Status}
	}
	if len(filter.Priority) > 0 {
		mongoFilter["priority"] = bson.M{"$in": filter.Priority}
	}

	findOpts := options.Find()
	if filter.Limit > 0 {
		findOpts.SetLimit(filter.Limit)
	}
	if filter.Offset > 0 {
		findOpts.SetSkip(filter.Offset)
	}
	findOpts.SetSort(bson.M{"created_at": -1})

	cursor, err := r.collection.Find(ctx, mongoFilter, findOpts)
	if err != nil {
		return nil, 0, err
	}
	defer cursor.Close(ctx)

	if err := cursor.All(ctx, &tickets); err != nil {
		return nil, 0, err
	}

	total, err := r.collection.CountDocuments(ctx, mongoFilter)
	if err != nil {
		return nil, 0, err
	}

	return tickets, total, nil
}

// GetTicket fetches a single ticket by ID.
func (r *MongoRepository) GetTicket(ctx context.Context, id string) (*model.Ticket, error) {
	var ticket model.Ticket
	if err := r.collection.FindOne(ctx, bson.M{"_id": id}).Decode(&ticket); err != nil {
		if err == mongo.ErrNoDocuments {
			return nil, nil
		}
		return nil, err
	}
	return &ticket, nil
}

// CreateTicket inserts a new ticket.
func (r *MongoRepository) CreateTicket(ctx context.Context, ticket *model.Ticket) error {
	ticket.CreatedAt = time.Now()
	ticket.UpdatedAt = time.Now()
	_, err := r.collection.InsertOne(ctx, ticket)
	return err
}

// UpdateTicket updates an existing ticket.
func (r *MongoRepository) UpdateTicket(ctx context.Context, ticket *model.Ticket) error {
	ticket.UpdatedAt = time.Now()
	filter := bson.M{"_id": ticket.ID}
	update := bson.M{
		"$set": bson.M{
			"status":      ticket.Status,
			"priority":    ticket.Priority,
			"assignedTo":  ticket.AssignedTo,
			"updated_at":  ticket.UpdatedAt,
		},
	}
	_, err := r.collection.UpdateOne(ctx, filter, update)
	return err
}

var _ Repository = (*MongoRepository)(nil)
